from sgmllib import SGMLParser
import re


from infra.logging import logger
from infra.exception import *
from web.factory import EntityFactoryManager
from web.filter.UrlDataFilter import UrlDataFilter
from web.entity.NoneEntity import NoneEntity

# TODO: move to constants.py

RELEVANCE_FACTOR_TITLE = 10
RELEVANCE_FACTOR_H1 = 9 
RELEVANCE_FACTOR_H2 = 8 
RELEVANCE_FACTOR_H3 = 7 
RELEVANCE_FACTOR_H4 = 6 
RELEVANCE_FACTOR_H5 = 5 
RELEVANCE_FACTOR_H6 = 4 
RELEVANCE_FACTOR_HREF = 3 


class HtmlParser(SGMLParser):

	def __init__(self, urlFilter, urlValidator): 
		SGMLParser.__init__(self)
		self.urlFilter_ = urlFilter 
		self.urlValidator_ = urlValidator
		log = logger.getLogger()

		isInvariant = False
		try:
			currencyMgr = EntityFactoryManager.findFactory("EUR")
			for currency in currencyMgr.getCurrencies():
				log.debug("Registering currency = %s...", currency.dump())
				self.entitydefs[re.sub("&|;", "", currency.toHTML())] = currency.toString()
				log.debug("Currency registered.")
		except EntityFactoryManager.NoSuchEntityFactory, e:
			log.error("caught exception NoSuchEntityFactory, reason: %s" % e)
			isInvariant = True
		except InvalidData.InvalidData, e:
			log.debug("caught exception InvalidData, reason: %s" % e)
			isInvariant = True

		if isInvariant:
			raise InvariantError.InvariantError("%s not initialized!" % self)

		self.resetState()

		log.debug("%s = %s" % (self, self.__dict__))


	def resetState(self):
		self.currentLink_ = None
		self.currentLinkText_ = NoneEntity()
		self.imgSrc_ = None
		self.imgWidth_ = 0
		self.imgHeight_ = 0
		self.relevanceFactor_ = 1
		self.isOption_ = False


	def parse(self, htmlDoc, webDoc):
		self.resetState()
		self.webDoc_ = webDoc
		log = logger.getLogger()
		log.info("Parsing html content ...")
		pat = re.compile("<([S|s]cript|SCRIPT).*?<\/([S|s]cript|SCRIPT)>", re.DOTALL)
		self.feed(pat.sub("", htmlDoc))
		self.close()
		log.info("Content parsed.")


	def start_option(self, attr):
		self.isOption_ = True


	def end_option(self):
		self.isOption_ = False


	def start_title(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_TITLE


	def end_title(self):
		self.relevanceFactor_ = 1


	def start_h1(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_H1


	def end_h1(self):
		self.relevanceFactor_ = 1


	def start_h2(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_H2


	def end_h2(self):
		self.relevanceFactor_ = 1


	def start_h3(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_H3


	def end_h3(self):
		self.relevanceFactor_ = 1


	def start_h4(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_H4


	def end_h4(self):
		self.relevanceFactor_ = 1


	def start_h5(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_H5


	def end_h5(self):
		self.relevanceFactor_ = 1


	def start_h6(self, attrs):
		self.relevanceFactor_ = RELEVANCE_FACTOR_H6


	def end_h6(self):
		self.relevanceFactor_ = 1


	def start_a(self, attrs):
		#If we encounter a nested a tag, end the current a tag and
		#start a new one.
		if self.currentLink_ != None:
			self.end_a()
		for attr, value in attrs:
			if attr == 'href':
				self.currentLink_ = value
				# REVISIT: decided whether increase relevance or not
				#self.relevanceFactor_ = RELEVANCE_FACTOR_HREF
				break


	def end_a(self):
		log = logger.getLogger()
		log.debug("Found end of url link = \"%s\", link name = \"%s\"" % (self.currentLink_, self.currentLinkText_.toString()))
		if self.currentLink_ and self.urlValidator_.validate(self.currentLink_): 
			abs_url, rel_url = self.urlFilter_.filter(self.currentLink_)
			if abs_url:
				try:
					webDocFactory = EntityFactoryManager.findFactory("WebDocument")
					webDocFactory.createEntity([-1, -1, abs_url, rel_url, self.currentLinkText_, [], NoneEntity(), NoneEntity(), NoneEntity(), None, -1], self.webDoc_, self.relevanceFactor_)
				except EntityFactoryManager.NoSuchEntityFactory, e:
					log.error("Caught NoSuchEntityFactory exception, reason: %s" % e)
				except InvalidData.InvalidData, e:
					log.debug("Caught InvalidData exception, reason: %s" % e)

		else:
			log.debug("url = %s, is excluded from further processing." % self.currentLink_)

		self.currentLink_ = None
		self.currentLinkText_ = NoneEntity()
		self.relevanceFactor_ = 1


	def handle_data(self, data):
		log = logger.getLogger()
		log.debug("Found data = \"%s\"." % data)  

		# ignore data in search forms
		if not self.isOption_:
			data = self.filter_data(data)
			if data:
			
				try:
					entityFactory = EntityFactoryManager.findFactory(data)
					entity = entityFactory.createEntity(data, self, self.relevanceFactor_)
					if self.currentLink_:
						self.currentLinkText_ = entity 
				except EntityFactoryManager.NoSuchEntityFactory, e:
					log.error("Caught NoSuchEntityFactory exception, reason: %s" % e)
				except InvalidData.InvalidData, e:
					log.debug("Caught InvalidData exception, reason: %s" % e)
		else:
			log.debug("Will ignore it as in a search form.")
			
	# EntityFactory callback
	def onLiteral(self, literal, lexer):
		log = logger.getLogger()
		
		if not self.currentLink_:
			literal.buildNamedEntities(lexer)
			self.webDoc_.onLiteral(literal)
		else: 
			log.debug("Will not build named entities as the literal = '%s' has been created from a link." % literal.getName())
		
		
		'''
		literal.buildNamedEntities(lexer, relevanceFactor)
		self.webDoc_.onLiteral(literal, self.currentLink_ != None)
		'''
		
		
		
	def onDate(self, date):
		self.webDoc_.onDate(date)

	def onWebDocument(self, webDoc):
		self.webDoc_.onWebDocument(webDoc)
		
	
	def onCurrency(self, currency):
		self.webDoc_.onCurrency(currency)


	def onImage(self, image):
		self.webDoc_.onImage(image)


	def onDuration(self, duration):
		self.webDoc_.onDuration(duration)


	def onNumber(self, number):
		self.webDoc_.onNumber(number)


	def onPriceTag(self, priceTag):
		self.webDoc_.onPriceTag(priceTag)



	def start_img(self, attrs):
		# should be called by sgml, but it's not :(
		if self.imgSrc_:
			self.end_img()

		for attr, value in attrs:
			# TODO: add image extension to config
			if attr == "src" and (value.find("jpg") != -1 or value.find("gif") != -1):
				self.imgSrc_ = value
			if attr == "width":
				self.imgWidth_ = int(value)
			if attr == "height":
				self.imgHeight_ = int(value)


	def end_img(self):
		log = logger.getLogger()
		try:
			imageFactory = EntityFactoryManager.findFactory("Image")
			imageFactory.createEntity([self.imgSrc_, self.imgWidth_, self.imgHeight_], self.webDoc_, self.relevanceFactor_)
		except EntityFactoryManager.NoSuchEntityFactory, e:
			log.error("Caught NoSuchEntityFactory exception, reason: %s" % e)
		except InvalidData.InvalidData, e:
			log.debug("Caught InvalidData exception, reason: %s" % e)

		self.imgSrc_ = None
		self.imgHeight_ = 0
		self.imgWidth_ = 0


	def filter_data(self, data):
		dataFilter = UrlDataFilter()
		return dataFilter.filter(data)
		
